package com.towel.sound;
import java.io.InputStream;
import javax.sound.sampled.AudioSystem;
import javax.sound.sampled.DataLine;
import javax.sound.sampled.LineUnavailableException;
import javax.sound.sampled.SourceDataLine;
/**
* Represents a playing Streamed. The playing noise can be paused or stopped. Once
* stopped, it cannot be reactivated again.
*
* @author Vin�cius
*/
public class PlayingStreamed implements Runnable
{
private volatile boolean isPaused = false;
private volatile boolean isFinished = false;
private Streamed stream;
/**
* Create a new playing noise. The noise will only be played when the run()
* method is called. Normally, it's thread pool responsibility to play the
* noise.
*
* @param noise The noise that will play.
*/
PlayingStreamed(Streamed stream)
{
isPaused = false;
isFinished = false;
this.stream = stream;
}
/**
* Pauses the noise, so it can be resumed later.
*
* @param pause True to pause the noise, false to resume.
*/
public void setPaused(boolean pause)
{
isPaused = pause;
}
/**
* Stop the noise. The noise may take a while to stop.
*/
public void stop()
{
isFinished = true;
}
/**
* Indicate if this noise is in paused state.
*
* @return True if the noise is paused.
*/
public boolean isPaused()
{
return isPaused;
}
/**
* Indicate if this playsound already stopped. Finished PlayingSounds cannot
* be activated, so they should be discarded.
*
* @return True if the noise is stopped, false if not.
*/
public boolean isFinished()
{
return isFinished;
}
/**
* Create a new dataline with the given buffer size. The format that will be
* used is the same as the noise encapsulated by this class.
*
* @param bufferSize Size of the buffer.
* @return The new source data line.
* @throws LineUnavailableException If there's no more lines available for
* this noise.
*/
private SourceDataLine createDataLine(int bufferSize)
throws LineUnavailableException
{
DataLine.Info info = new DataLine.Info(SourceDataLine.class, stream
.getFormat());
SourceDataLine line = (SourceDataLine) AudioSystem.getLine(info);
line.open(stream.getFormat(), bufferSize);
return line;
}
/**
* Create a new buffer. The buffer size will vary according to the noise
* frame size and rate.
*
* @return The noise buffer.
*/
private byte[] createStreamedBuffer()
{
int bufferSize = stream.getFormat().getFrameSize()
* Math.round(stream.getFormat().getSampleRate() / 10);
return new byte[bufferSize];
}
/**
* Plays the noise.
*/
public void run()
{
if (isFinished)
throw new IllegalStateException("Sound already played.");
SourceDataLine line = null;
try
{
byte[] buffer = createStreamedBuffer();
line = createDataLine(buffer.length);
InputStream input = stream.newInputStream();
line.start();
int numBytesRead = 0;
while (numBytesRead != -1 && !isFinished())
{
if (isPaused())
{
Thread.yield();
continue;
}
numBytesRead = input.read(buffer, 0, buffer.length);
if (numBytesRead != -1)
line.write(buffer, 0, numBytesRead);
}
}
catch (Exception e)
{
// Stops playing immediatelly
}
finally
{
stop();
if (line != null)
{
line.drain();
line.close();
}
}
}
/**
* Return the Streamed that is being played by this PlayingStreamed.
*
* @return The Streamed that is being played.
*/
public Streamed getStream()
{
return stream;
}
}